#include "Text/SourceText.hpp"
#include <cstddef>

size_t SourceText::GetLineIndex(size_t position)
{
    size_t lower = 0;
    size_t upper = Lines.size() - 1;

    while (lower <= upper)
    {
        size_t index = lower + (upper - lower) / 2;
        size_t start = Lines[index].Start;

        if (position == start)
            return index;

        if (start > position)
        {
            upper = index - 1;
        }
        else
        {
            lower = index + 1;
        }
    }

    return lower - 1;
}

void SourceText::AddLine(std::vector<TextLine> &result, SourceText *sourceText, size_t position, size_t lineStart, size_t lineBreakWidth)
{
    auto lineLength                   = position - lineStart;
    auto lineLengthIncludingLineBreak = lineLength + lineBreakWidth;
    auto line                         = TextLine(sourceText, lineStart, lineLength, lineLengthIncludingLineBreak);
    result.push_back(line);
}
static int GetLineBreakWidth(std::string text, size_t position)
{
    char c = text[position];
    char l = position + 1 >= text.length() ? '\0' : text[position + 1];

    if (c == '\r' && l == '\n')
        return 2;

    if (c == '\r' || c == '\n')
        return 1;

    return 0;
}

std::vector<TextLine> SourceText::ParseLines(SourceText *sourceText, std::string text)
{
    std::vector<TextLine> result;

    size_t position  = 0;
    size_t lineStart = 0;

    while (position < text.length())
    {
        size_t lineBreakWidth = GetLineBreakWidth(text, position);

        if (lineBreakWidth == 0)
        {
            position++;
        }
        else
        {
            AddLine(result, sourceText, position, lineStart, lineBreakWidth);

            position += lineBreakWidth;
            lineStart = position;
        }
    }

    if (position >= lineStart)
        AddLine(result, sourceText, position, lineStart, 0);

    return result;
}
